package com.gzyj.jtt808.utils;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * @author lhj
 */
public class HexBytesUtil {
    /**
     * byte数组转16进制
     *
     * @param bytes
     * @return
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            // 使用String的format方法进行转换
            buf.append(String.format("%02x", new Integer(b & 0xff)));
        }
        return buf.toString();
    }

    /**
     * Hex转byte,hex只能含两个字符，如果是一个字符byte高位会是0
     */
    public static byte hexTobyte(String hex) {
        return (byte) Integer.parseInt(hex, 16);
    }

    /**
     * Hex转byte[]，两种情况，Hex长度为奇数最后一个字符会被舍去
     */
    public static byte[] hexTobytes(String hex) {
        if (hex.length() < 1) {
            return null;
        } else {
            /*byte[] result = new byte[hex.length() / 2];
            int j = 0;
            for(int i = 0; i < hex.length(); i+=2) {
                result[j++] = (byte)Integer.parseInt(hex.substring(i,i+2), 16);
            }
            return result;*/
            int l = hex.length() / 2;
            byte[] ret = new byte[l];
            for (int i = 0; i < l; i++) {
                ret[i] = (byte) Integer.valueOf(hex.substring(i * 2, i * 2 + 2), 16).byteValue();
            }
            return ret;
        }
    }

    public static byte[] readByOffset(ByteBuf byteBuf, int length) {
        if (byteBuf.hasArray()) {
            byte[] temp = new byte[length];
            byteBuf.readBytes(temp);
            return temp;
        }
        return null;
    }


    public static int byteArrayToInt(byte[] bytes) {
        int value = 0;
        // 由高位到低位
        for (int i = 0; i < 4; i++) {
            int shift = (4 - 1 - i) * 8;
            value += (bytes[i] & 0x000000FF) << shift;// 往高位游
        }
        return value;
    }

    public static byte[] readZy(byte[] in) {
        String hex = bytesToHex(in).toLowerCase().replaceAll("5a01", "5b").replaceAll("5a02", "5a")
                .replaceAll("5e01", "5d")
                .replaceAll("5e02", "5e");

        return hexTobytes(hex);
    }

    public static ByteBuf readZy(String in) {
        String hex = in.replaceAll("7d02", "7e").replaceAll("7d01", "7d");

        ByteBuf out = Unpooled.buffer();
        out.writeBytes(hexTobytes("7e" + hex + "7e"));
        return out;
    }

    public static String parseString(byte[] temp) {
        int length = 0;
        for (int i = 0; i < temp.length; ++i) {
            if (temp[i] == 0) {
                length = i;
                break;
            }
        }
        if (length == 0) {
            // 没有空
            return new String(temp, Charset.forName("GBK"));
        } else {
            return new String(temp, 0, length, Charset.forName("GBK"));
        }

    }

    public static String readString(ByteBuf buf, int len) {
        byte[] bytes = new byte[len];
        buf.readBytes(bytes);

        return new String(bytes, Charset.forName("GBK"));
    }

    private static byte[] subByte(byte[] b, int off, int length) {
        byte[] b1 = new byte[length];
        System.arraycopy(b, off, b1, 0, length);
        return b1;
    }

    /**
     * 定长字符串右补齐
     *
     * @param data
     * @param len
     * @return
     */
    public static byte[] WriteStringPadRight(String data, int len) {
        byte[] bytes = data.getBytes(Charset.forName("GBK"));

        int fillLength = bytes.length - len;
        if (fillLength > 0) {
            return subByte(bytes, 0, len);
        } else if (fillLength < 0) {
            byte[] res = new byte[len];
            for (int i = 0; i < bytes.length; i++) {

                res[i] = bytes[i];

            }
            return res;

        } else {
            return bytes;
        }
    }

    public static byte[] WriteStringPadRightASCII(String data, int len) {
        byte[] bytes = data.getBytes(Charset.forName("US-ASCII"));

        int fillLength = bytes.length - len;
        if (fillLength > 0) {
            return subByte(bytes, 0, len);
        } else if (fillLength < 0) {
            byte[] res = new byte[len];
            for (int i = 0; i < bytes.length; i++) {

                res[i] = bytes[i];

            }
            return res;

        } else {
            return bytes;
        }
    }

    private static byte[] byteMerger(byte[] bt1, byte[] bt2) {
        byte[] bt3 = new byte[bt1.length + bt2.length];
        System.arraycopy(bt1, 0, bt3, 0, bt1.length);
        System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
        return bt3;
    }

    /**
     * 定长字符串左补齐
     *
     * @param data
     * @param len
     * @return
     */
    public static byte[] WriteStringPadLeft(String data, int len) {
        byte[] bytes = data.getBytes(Charset.forName("GBK"));

        int fillLength = bytes.length - len;

        if (fillLength > 0) {
            return subByte(bytes, 0, len);
        } else if (fillLength < 0) {

            byte[] left = new byte[-1 * fillLength];
            return byteMerger(left, bytes);
        } else {
            return bytes;
        }

    }

    public static byte[] WriteBCD(String val, int len) {
        StringBuffer bcdText = new StringBuffer(val);
        int startIndex = 0;
        int noOfZero = len - bcdText.length();
        if (noOfZero > 0) {
            StringBuffer s = new StringBuffer();
            for (int i = 0; i < noOfZero; i++) {
                s.append('0');
            }

            bcdText = bcdText.insert(startIndex, s.toString());
        }
        int byteIndex = 0;
        int count = len / 2;
        byte[] spanFree = new byte[count];
        byte[] bcdSpan = bcdText.toString().getBytes();
        while (startIndex < bcdText.length() && byteIndex < count) {

            spanFree[byteIndex++] = (byte) Integer.parseInt(new String(subByte(bcdSpan, startIndex, 2)), 16); //Convert.ToByte(bcdSpan.Slice(startIndex, 2).ToString(), 16);
            startIndex += 2;
        }
        return spanFree;
    }

    public static String ReadBCD(byte[] readOnlySpan, int len) {
        int count = len / 2;
        StringBuffer bcdSb = new StringBuffer(count);
        for (int i = 0; i < count; i++) {
            bcdSb.append(bytesToHex(new byte[]{readOnlySpan[i]}));
        }
        return bcdSb.toString();
    }

    public static byte[] Skip(int count) {
        byte[] bytes = new byte[count - 1];
        for (int i = 0; i < count - 1; i++) {
            bytes[i] = 0x00;
        }
        return bytes;
    }


    /**
     * @功能: 10进制串转为BCD码
     * @参数: 10进制串
     * @结果: BCD码
     */
    public static byte[] str2Bcd(String asc) {
        int len = asc.length();
        int mod = len % 2;
        if (mod != 0) {
            asc = "0" + asc;
            len = asc.length();
        }
        byte abt[] = new byte[len];
        if (len >= 2) {
            len = len / 2;
        }
        byte bbt[] = new byte[len];
        abt = asc.getBytes();
        int j, k;
        for (int p = 0; p < asc.length() / 2; p++) {
            if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
                j = abt[2 * p] - '0';
            } else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
                j = abt[2 * p] - 'a' + 0x0a;
            } else {
                j = abt[2 * p] - 'A' + 0x0a;
            }
            if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
                k = abt[2 * p + 1] - '0';
            } else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
                k = abt[2 * p + 1] - 'a' + 0x0a;
            } else {
                k = abt[2 * p + 1] - 'A' + 0x0a;
            }
            int a = (j << 4) + k;
            byte b = (byte) a;
            bbt[p] = b;
        }
        return bbt;
    }

    private static byte IntToBcd(int value) {
        byte result = 0;
        if (value <= 0xFF) {
            //19 00010011
            //0001 1001
            int high = value / 10;
            int low = value % 10;
            result = (byte) (high << 4 | low);
        }
        return result;
    }

    public static byte[] IntToBcd(int value, byte[] list, int count) {

        int level = count - 1;
        int high = value / 100;
        int low = value % 100;
        if (high > 0) {
            IntToBcd(high, list, --count);
        }
        byte res = (byte) (((low / 10) << 4) + (low % 10));
        list[level] = res;
        return list;
    }

    public static int BcdToInt(byte value) {
        int high = value >> 4;
        int low = value & 0xF;
        int number = 10 * high + low;
        return number;
    }

    public static byte[] WriteDateTime_yyMMddHHmmss(Date date) {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        calendar.setTime(date);
        int yy = calendar.get(Calendar.YEAR) - 2000;
        byte[] res = new byte[6];
        res[0] = IntToBcd(yy);
        int month = calendar.get(Calendar.MONTH);
        if (month + 1 > 12) {
            month = 1;
        } else {
            month += 1;
        }
        res[1] = IntToBcd(month);
        res[2] = IntToBcd(calendar.get(Calendar.DATE));
        res[3] = IntToBcd(calendar.get(Calendar.HOUR_OF_DAY));
        res[4] = IntToBcd(calendar.get(Calendar.MINUTE));
        res[5] = IntToBcd(calendar.get(Calendar.SECOND));


        return res;

    }

    public static byte[] WriteDateTime_HHmmssfff(Date date) {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        calendar.setTime(date);
        byte[] res = new byte[5];
        res[0] = IntToBcd(calendar.get(Calendar.HOUR_OF_DAY));
        res[1] = IntToBcd(calendar.get(Calendar.MINUTE));
        res[2] = IntToBcd(calendar.get(Calendar.SECOND));
        byte[] t = new byte[2];
        byte[] rs = IntToBcd(calendar.get(Calendar.MILLISECOND), t, 2);
        res[3] = rs[0];
        res[4] = rs[1];


        return res;
    }

    public static byte[] WriteDateTime_YYMMDD(Date date) {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        calendar.setTime(date);
        int yy = calendar.get(Calendar.YEAR) - 2000;
        byte[] res = new byte[3];
        res[0] = IntToBcd(yy);
        int month = calendar.get(Calendar.MONTH);
        if (month + 1 > 12) {
            month = 1;
        } else {
            month += 1;
        }
        res[1] = IntToBcd(month);
        res[2] = IntToBcd(calendar.get(Calendar.DATE));
        return res;
    }


    public static byte[] WriteDateTime_YYMMDD4(Date date) {

        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        calendar.setTime(date);
        int yy = calendar.get(Calendar.YEAR) - 2000;
        byte[] res = new byte[4];
        res[0] = IntToBcd(20);
        res[1] = IntToBcd(yy);
        int month = calendar.get(Calendar.MONTH);
        if (month + 1 > 12) {
            month = 1;
        } else {
            month += 1;
        }
        res[2] = IntToBcd(month);
        res[3] = IntToBcd(calendar.get(Calendar.DATE));
        return res;
    }

    public static String ReadDateTime_YYMMDD4(byte[] readOnlySpan) {
        int year = BcdToInt(readOnlySpan[0]) * 100 + BcdToInt(readOnlySpan[1]);
        int month = BcdToInt(readOnlySpan[2]);

        if (month - 1 < 0) {
            month = 0;
        } else {
            month -= 1;
        }

        int day = BcdToInt(readOnlySpan[3]);
        Date now = new Date();
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(now);
        // 将时分秒,毫秒域清零
        cal1.set(Calendar.YEAR, year);
        cal1.set(Calendar.MONTH, month);
        cal1.set(Calendar.DATE, day);
        return sdf_date.format(cal1.getTime());
    }

    public static String ReadDateTime_YYMMDD(byte[] readOnlySpan) {
        int year = BcdToInt(readOnlySpan[0]) + 2000;
        int month = BcdToInt(readOnlySpan[1]);

        if (month - 1 < 0) {
            month = 0;
        } else {
            month -= 1;
        }

        int day = BcdToInt(readOnlySpan[2]);
        Date now = new Date();
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(now);
        // 将时分秒,毫秒域清零
        cal1.set(Calendar.YEAR, year);
        cal1.set(Calendar.MONTH, month);
        cal1.set(Calendar.DATE, day);
        return sdf_date.format(cal1.getTime());
    }


    private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private final static SimpleDateFormat sdf_date = new SimpleDateFormat("yyyy-MM-dd");
    private final static SimpleDateFormat sdf_ss = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");


    public static String ReadDateTime_yyMMddHHmmss(byte[] readOnlySpan) {

        int year = BcdToInt(readOnlySpan[0]) + 2000;
        int month = BcdToInt(readOnlySpan[1]);

        if (month - 1 < 0) {
            month = 0;
        } else {
            month -= 1;
        }

        int day = BcdToInt(readOnlySpan[2]);
        int hour = BcdToInt(readOnlySpan[3]);
        int minute = BcdToInt(readOnlySpan[4]);
        int second = BcdToInt(readOnlySpan[5]);
        Date now = new Date();
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(now);
        // 将时分秒,毫秒域清零
        cal1.set(Calendar.YEAR, year);
        cal1.set(Calendar.MONTH, month);
        cal1.set(Calendar.DATE, day);
        cal1.set(Calendar.HOUR_OF_DAY, hour);
        cal1.set(Calendar.MINUTE, minute);
        cal1.set(Calendar.SECOND, second);
        return sdf.format(cal1.getTime());
    }

    public static String ReadDateTime_HHmmssfff(byte[] readOnlySpan) {
        Date now = new Date();
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(now);
        int hour = BcdToInt(readOnlySpan[0]);
        int minute = BcdToInt(readOnlySpan[1]);
        int second = BcdToInt(readOnlySpan[2]);

        cal1.set(Calendar.HOUR_OF_DAY, hour);
        cal1.set(Calendar.MINUTE, minute);
        cal1.set(Calendar.SECOND, second);

        int fff = BcdToInt(readOnlySpan[3]) * 100 + BcdToInt(readOnlySpan[4]);

        cal1.set(Calendar.MILLISECOND, fff);

        return sdf_ss.format(cal1.getTime());
    }

    public static byte[] WriteBigNumber(String value, int len) {
        byte[] spanFree = new byte[len];
        long number = value == null || value.length() == 0 ? 0 : Long.valueOf(value);
        for (int i = len - 1; i >= 0; i--) {
            spanFree[i] = (byte) (number & 0xFF);  //取低8位
            number = number >> 8;
        }
        return spanFree;
    }

    public static byte[] short2ByteNew(short x) {
        byte high = (byte) (0x00FF & (x >> 8));//定义第一个byte
        byte low = (byte) (0x00FF & x);//定义第二个byte
//        System.out.println(high);//打印第一个byte值
//        System.out.println(low);//打印第二个byte值
        byte[] bytes = new byte[2];
        bytes[0] = high;
        bytes[1] = low;
        return bytes;
    }


    public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        byte[] bytes = WriteDateTime_YYMMDD4(sdf.parse("2018-08-16"));
        System.out.println(bytesToHex(bytes));
        System.out.println(ReadDateTime_YYMMDD4(bytes));
    }

}
